import { message } from "@/utils/message";
import menuApi, { type MenuNode, type MenuPayload } from "@/api/system/menu";
import { useDialog } from "@/composables/useDialog";
import { reactive, ref, onMounted, h } from "vue";
import type { FormItemProps } from "../utils/types";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils";
import { ElMessageBox } from "element-plus";
import { handleTree } from "@/utils/tree";

interface AdaptedMenu extends FormItemProps {
  id: number;
  parentId: number;
  type?: string;
  clientType?: string;
  status?: number;
  isVisible?: number;
  children?: Array<AdaptedMenu>;
}

const DEFAULT_FORM: FormItemProps = {
  menuType: 0,
  higherMenuOptions: [],
  parentId: 0,
  title: "",
  name: "",
  path: "",
  component: "",
  rank: 99,
  redirect: "",
  icon: "",
  extraIcon: "",
  enterTransition: "",
  leaveTransition: "",
  activePath: "",
  auths: "",
  frameSrc: "",
  frameLoading: true,
  keepAlive: false,
  hiddenTag: false,
  fixedTag: false,
  showLink: true,
  showParent: false,
  clientType: "admin",
  status: 1
};

const toSafeNumber = (value: unknown, fallback = 0) => {
  const num = Number(value);
  return Number.isFinite(num) ? num : fallback;
};

const toSafeString = (value: unknown) =>
  typeof value === "string" ? value : "";

const toSafeBoolean = (value: unknown, fallback = false) => {
  if (value === undefined || value === null) return fallback;
  if (typeof value === "boolean") return value;
  if (typeof value === "number") return value === 1;
  if (typeof value === "string") {
    const normalised = value.toLowerCase();
    return ["1", "true", "yes", "on"].includes(normalised);
  }
  return fallback;
};

const mapMenuType = (type?: string): number => {
  const t = (type ?? "").toLowerCase();
  switch (t) {
    case "iframe":
      return 1;
    case "link":
    case "external":
    case "external_link":
      return 2;
    case "button":
      return 3;
    default:
      return 0;
  }
};

const menuTypeToBackend = (menuType: number): string => {
  switch (menuType) {
    case 1:
      return "iframe";
    case 2:
      return "link";
    case 3:
      return "button";
    default:
      return "menu";
  }
};

const compactMeta = (meta: Record<string, any>) => {
  const result: Record<string, any> = {};
  Object.entries(meta).forEach(([key, value]) => {
    if (value === undefined) return;
    if (typeof value === "string" && value === "") return;
    result[key] = value;
  });
  return result;
};

const transformMenuTree = (
  nodes: Array<MenuNode> | undefined,
  parentId = 0
): Array<AdaptedMenu> => {
  if (!Array.isArray(nodes)) return [];
  return nodes.map(node => {
    const meta = node.meta ?? {};
    const menuType = mapMenuType(node.type);
    const showLink =
      menuType === 3 ? false : toSafeBoolean(meta.showLink, true);

    const adapted: AdaptedMenu = {
      id: toSafeNumber(node.id, 0),
      parentId,
      menuType,
      higherMenuOptions: [],
      title: meta.title ?? node.name ?? String(node.id),
      name: node.name ?? "",
      path: menuType === 3 ? "" : toSafeString(node.path ?? ""),
      component: menuType === 3 ? "" : toSafeString(node.component ?? ""),
      rank: toSafeNumber(meta.rank ?? node.sort ?? 0, 0),
      redirect: menuType === 3 ? "" : toSafeString(node.redirect ?? ""),
      icon: meta.icon ?? "",
      extraIcon: toSafeString(meta.extraIcon),
      enterTransition: toSafeString(meta.enterTransition),
      leaveTransition: toSafeString(meta.leaveTransition),
      activePath: toSafeString(meta.activePath),
      auths: node.permission_code ?? "",
      frameSrc:
        menuType === 1 ? toSafeString(meta.frameSrc ?? meta.frame_src) : "",
      frameLoading:
        menuType === 1 ? toSafeBoolean(meta.frameLoading, true) : true,
      keepAlive: menuType === 0 ? toSafeBoolean(meta.keepAlive, false) : false,
      hiddenTag: menuType === 0 ? toSafeBoolean(meta.hiddenTag, false) : false,
      fixedTag: menuType === 0 ? toSafeBoolean(meta.fixedTag, false) : false,
      showLink,
      showParent:
        menuType === 3 ? false : toSafeBoolean(meta.showParent, false),
      clientType: node.client_type ?? "admin",
      status: toSafeNumber(node.status, showLink ? 1 : 0),
      isVisible: toSafeNumber(node.is_visible, showLink ? 1 : 0),
      type: node.type ?? menuTypeToBackend(menuType),
      children: transformMenuTree(node.children, toSafeNumber(node.id, 0))
    };

    return adapted;
  });
};

const filterMenuTree = (nodes: Array<AdaptedMenu>, keyword: string) => {
  if (!keyword) return nodes;
  const lower = keyword.toLowerCase();
  const travel = (items: Array<AdaptedMenu>): Array<AdaptedMenu> => {
    return items
      .map(item => {
        const children = item.children ? travel(item.children) : [];
        const matched =
          item.title.toLowerCase().includes(lower) ||
          item.name.toLowerCase().includes(lower);
        if (matched || children.length) {
          return { ...item, children };
        }
        return null;
      })
      .filter(Boolean) as Array<AdaptedMenu>;
  };
  return travel(nodes);
};

const buildPayload = (form: FormItemProps): MenuPayload => {
  const menuType = form.menuType ?? 0;
  const backendType = menuTypeToBackend(menuType);
  const effectiveShowLink = menuType === 3 ? false : form.showLink;

  return {
    parent_id: form.parentId || 0,
    name: form.name || form.title,
    identifier: form.name || form.title,
    path: menuType === 3 ? "" : form.path || "",
    component: menuType === 3 ? "" : form.component || "",
    redirect: menuType === 3 ? "" : form.redirect || "",
    permission_code: form.auths || null,
    client_type: form.clientType ?? "admin",
    sort: toSafeNumber(form.rank, 0),
    is_visible: effectiveShowLink ? 1 : 0,
    status: form.status ?? 1,
    type: backendType,
    meta: compactMeta({
      title: form.title,
      icon: form.icon || "",
      rank: toSafeNumber(form.rank, 0),
      showLink: effectiveShowLink,
      showParent: menuType === 3 ? false : form.showParent,
      extraIcon: form.extraIcon || undefined,
      enterTransition:
        menuType === 0 || menuType === 1
          ? form.enterTransition || undefined
          : undefined,
      leaveTransition:
        menuType === 0 || menuType === 1
          ? form.leaveTransition || undefined
          : undefined,
      activePath:
        menuType === 0 ? toSafeString(form.activePath) || undefined : undefined,
      keepAlive: menuType === 0 ? Boolean(form.keepAlive) : undefined,
      hiddenTag: menuType === 0 ? Boolean(form.hiddenTag) : undefined,
      fixedTag: menuType === 0 ? Boolean(form.fixedTag) : undefined,
      frameSrc:
        menuType === 1 ? toSafeString(form.frameSrc) || undefined : undefined,
      frameLoading: menuType === 1 ? form.frameLoading !== false : undefined
    })
  };
};

const getMenuType = (type: number, text = false) => {
  switch (type) {
    case 0:
      return text ? "菜单" : "primary";
    case 1:
      return text ? "iframe" : "warning";
    case 2:
      return text ? "外链" : "danger";
    case 3:
      return text ? "按钮" : "info";
    default:
      return text ? "菜单" : "primary";
  }
};

export function useMenu() {
  const form = reactive<{ title: string }>({
    title: ""
  });

  const dataList = ref<AdaptedMenu[]>([]);
  const loading = ref(true);
  const { openDialog: openMenuDialog } = useDialog();

  const columns: TableColumnList = [
    {
      label: "菜单名称",
      prop: "title",
      align: "left",
      cellRenderer: ({ row }) => (
        <>
          <span class="inline-block mr-1">
            {h(useRenderIcon(row.icon || "ep:menu"), {
              style: { paddingTop: "1px" }
            })}
          </span>
          <span>{row.title}</span>
        </>
      )
    },
    {
      label: "菜单类型",
      prop: "menuType",
      width: 100,
      cellRenderer: ({ row, props }) => (
        <el-tag
          size={props.size}
          type={getMenuType(row.menuType)}
          effect="plain"
        >
          {getMenuType(row.menuType, true)}
        </el-tag>
      )
    },
    {
      label: "路由路径",
      prop: "path"
    },
    {
      label: "组件路径",
      prop: "component",
      formatter: ({ path, component }) =>
        isAllEmpty(component) ? path : component
    },
    {
      label: "权限标识",
      prop: "auths"
    },
    {
      label: "排序",
      prop: "rank",
      width: 100
    },
    {
      label: "隐藏",
      prop: "showLink",
      formatter: ({ showLink }) => (showLink ? "否" : "是"),
      width: 100
    },
    {
      label: "操作",
      fixed: "right",
      width: 210,
      slot: "operation"
    }
  ];

  async function onSearch() {
    loading.value = true;
    try {
      const { list } = await menuApi.fetchList();
      const keyword = String(form.title ?? "").trim();
      const tree = transformMenuTree(list);
      dataList.value = keyword ? filterMenuTree(tree, keyword) : tree;
    } finally {
      loading.value = false;
    }
  }

  function handleSelectionChange(_val: AdaptedMenu[]) {
    // 保留接口，实际逻辑按需扩展
  }

  function resetForm(formEl) {
    if (!formEl) return;
    formEl.resetFields();
    onSearch();
  }

  function formatHigherMenuOptions(treeList) {
    if (!treeList || !treeList.length) return [];
    const newTreeList: Array<any> = [];
    for (let i = 0; i < treeList.length; i++) {
      const current = { ...treeList[i] };
      current.title = String(current.title ?? "");
      current.children = formatHigherMenuOptions(current.children || []);
      newTreeList.push(current);
    }
    return newTreeList;
  }

  function openDialog(title = "新增", row?: AdaptedMenu) {
    openMenuDialog(() => import("../form.vue"), {
      title: `${title}菜单`,
      width: "45%",
      draggable: true,
      fullscreen: deviceDetection(),
      closeOnClickModal: false,
      props: {
        formInline: Object.assign(
          {},
          DEFAULT_FORM,
          {
            higherMenuOptions: formatHigherMenuOptions(
              cloneDeep(dataList.value)
            )
          },
          row ?? {}
        )
      },
      onConfirm: async (done, componentRef) => {
        const formComponent = componentRef as any;
        const valid = await formComponent?.submitForm?.();
        if (!valid) return false;
        const curData = formComponent?.getModel?.() as FormItemProps;
        if (!curData) return false;
        try {
          if (title === "新增") {
            await menuApi.create(buildPayload(curData));
            message(`已新增菜单「${curData.title}」`, {
              type: "success"
            });
          } else if (row?.id) {
            await menuApi.update(row.id, buildPayload(curData));
            message(`已更新菜单「${curData.title}」`, {
              type: "success"
            });
          }
          done();
          onSearch();
        } catch (error: any) {
          message(error?.message ?? "保存菜单失败", { type: "error" });
        }
        return false;
      }
    });
  }

  async function handleDelete(row: AdaptedMenu) {
    try {
      await ElMessageBox.confirm(
        `确认删除菜单「${row.title}」吗？`,
        "删除确认",
        {
          type: "warning",
          confirmButtonText: "确定",
          cancelButtonText: "取消"
        }
      );
    } catch {
      return;
    }
    try {
      await menuApi.remove(row.id);
      message(`已删除菜单「${row.title}」`, {
        type: "success"
      });
      onSearch();
    } catch (error: any) {
      message(error?.message ?? "删除菜单失败", { type: "error" });
    }
  }

  onMounted(() => {
    onSearch();
  });

  return {
    form,
    loading,
    columns,
    dataList,
    onSearch,
    resetForm,
    openDialog,
    handleDelete,
    handleSelectionChange
  };
}
